import type { PageType } from '../../page_handler/type'
import { getCurrentHostname, logger } from '../../../types/constants'
import { EventEmitter } from '../../event_emitter'
import { PollingHandler } from '../../polling_handler'
import { TimerManager } from '../../timer_manager'
import { BaseDestructible } from '../base_destructible'

export type StorageScope = 'global' | 'domain' | 'pageType' | 'module'

export interface StorageConfig {
  useNamespace: boolean
  useDomainIsolation: boolean
  namespaceKeyStrategy: 'prefix' | 'suffix'
  keySeparator?: string // 键名分隔符（默认'::'）
  defaultScope?: StorageScope // 默认存储作用域
  pageType?: PageType // 当前页面类型（可选）
}

export interface OptionsConfig {
  useNamespace?: boolean
  useDomainIsolation?: boolean
  scope?: StorageScope
  pageType?: PageType
}

export interface EnhancedOptionsConfig extends OptionsConfig {
  includeGlobal?: boolean
  prefix?: string | undefined
}

export interface StorageModule {
  get: <T>(key: string, defaultValue?: T, options?: OptionsConfig) => T
  set: <T>(key: string, value: T, options?: OptionsConfig) => void
  delete: (key: string, skipConvert?: boolean, options?: OptionsConfig) => void
  empty: () => void
  deleteBatch: (options?: EnhancedOptionsConfig) => void
  getAll: (options?: EnhancedOptionsConfig, skipConvert?: boolean) => Record<string, any>
  getAllGlobal: () => Record<string, any>
  migrateDomainData: (oldDomain: string, newDomain: string) => void
}

/**
 * 【基础模块类】 GM_函数存储 - 使用浏览器清空所有缓存也不受影响，应该是使用浏览器扩展的私有存储空间
 * 提供支持域名隔离的存储管理等基础功能
 */
export abstract class GMStorage extends BaseDestructible {
  abstract readonly id: string
  protected _name: string = 'gm-storage'
  config: Record<string, any> = {}

  readonly eventEmitter: EventEmitter = EventEmitter.getInstance()
  readonly timerManager: TimerManager = TimerManager.getInstance()
  readonly pollingHandler: PollingHandler = PollingHandler.getInstance()
  private readonly domain: string = getCurrentHostname()
  // 存储隔离策略配置
  protected storageConfig: StorageConfig = {
    useNamespace: true, // 默认使用模块命名空间
    useDomainIsolation: true, // 默认启用域名隔离
    namespaceKeyStrategy: 'prefix' as 'prefix' | 'suffix', // 命名空间键策略
    defaultScope: 'pageType',
    keySeparator: '::',
    pageType: 'default',
  }

  protected storageInternal: StorageModule = {
    /**
     * 获取存储值（支持域名隔离）
     * @param key 键名
     * @param defaultValue 默认值
     * @param options 作用域选项
     * @returns 存储的值或默认值
     */
    get: <T>(key: string, defaultValue?: T, options?: OptionsConfig): T => {
      const finalKey = this.getFinalKey(key, options)
      const value = GM_getValue(finalKey, defaultValue as T)

      // 确保返回值类型与T一致
      if (value === undefined || value === null) {
        return defaultValue as T
      }
      return value as T
    },

    /**
     * 设置存储值（支持域名隔离）
     * @param key 键名
     * @param value 值
     * @param options 作用域选项
     */
    set: (key: string, value: any, options?: OptionsConfig): void => {
      const finalKey = this.getFinalKey(key, options)
      GM_setValue(finalKey, value)
    },

    /**
     * 删除存储值（支持域名隔离）
     * @param key 键名
     * @param skipConvert 是否跳过键名转换
     * @param options 作用域选项
     */
    delete: (key: string, skipConvert: boolean = false, options?: OptionsConfig): void => {
      const finalKey = skipConvert ? key : this.getFinalKey(key, options)
      GM_deleteValue(finalKey)
      // logger.primary(`[${this._name}] 已删除键：${finalKey}`)
    },

    /**
     * 清空所有存储值
     */
    empty: () => {
      GM_listValues().forEach((key) => {
        GM_deleteValue(key)
      })
    },

    /**
     * 批量删除当前作用域中指定的存储键值对
     * @param options 作用域选项
     * }
     */
    deleteBatch: (options?: EnhancedOptionsConfig): void => {
      const allConfig = this.storageInternal.getAll(options, true)
      let deletedCount = 0

      Object.keys(allConfig).forEach((key) => {
        deletedCount++
        this.storageInternal.delete(key, true, options)
      })

      if (deletedCount === 0) {
        logger.warn(`[Storage] ⚠️ 没有找到任何键，跳过删除 (作用域: ${this.getScopeDescription(options)})`)
      }
      else {
        logger.warn(`[Storage] 已删除 ${deletedCount} 个键 (作用域: ${this.getScopeDescription(options)})`)
      }
    },

    /**
     * 获取所有存储键值对
     * @param options 作用域选项
     * @param skipConvert 是否跳过键名转换
     */
    getAll: (options?: EnhancedOptionsConfig, skipConvert: boolean = false): Record<string, any> => {
      const allKeys = GM_listValues()
      const result: Record<string, any> = {}

      allKeys.forEach((key: string) => {
        const shouldInclude = this.shouldIncludeKey(key, this.domain, options)
        if (shouldInclude) {
          if (skipConvert) {
            result[key] = GM_getValue(key)
            return
          }
          const displayKey = this.getDisplayKey(key, options)
          result[displayKey] = GM_getValue(key)
        }
      })

      return result
    },

    /**
     * 获取整个GM存储的所有键值对（包括其他模块）
     */
    getAllGlobal: (): Record<string, any> => {
      const allValues = GM_listValues()
      const globalValues: Record<string, any> = {}

      allValues.forEach((key: string) => {
        globalValues[key] = GM_getValue(key)
      })

      return globalValues
    },

    /**
     * 迁移数据到新域名（当网站域名变更时使用）
     * @param oldDomain 旧域名
     * @param newDomain 新域名
     */
    migrateDomainData: (oldDomain: string, newDomain: string): void => {
      const allKeys = GM_listValues()
      const domainPattern = this.storageConfig.namespaceKeyStrategy === 'prefix'
        ? `${oldDomain}_`
        : `_${oldDomain}`

      allKeys.forEach((key: string) => {
        if (key.includes(domainPattern)) {
          const newKey = key.replace(domainPattern, this.storageConfig.namespaceKeyStrategy === 'prefix'
            ? `${newDomain}_`
            : `_${newDomain}`)
          const value = GM_getValue(key)
          GM_setValue(newKey, value)
          GM_deleteValue(key)

          logger.info(`[Storage] 迁移键: ${key} -> ${newKey}`)
        }
      })
    },
  }

  // 公开的 storage 属性
  public get storage(): StorageModule {
    return this.storageInternal
  }

  /**
   * 配置存储策略
   * @param config 存储配置
   */
  protected configureStorage(config: StorageConfig): void {
    this.storageConfig = {
      ...this.storageConfig,
      ...config,
    }

    logger.info('[Storage] 更新存储配置', this.storageConfig)
  }

  /**
   * 获取最终存储键名（支持域名隔离）
   * @param key 原始键名
   * @param options 作用域选项
   */
  private getFinalKey(key: string, options?: OptionsConfig): string {
    const {
      useNamespace = this.storageConfig.useNamespace,
      useDomainIsolation = this.storageConfig.useDomainIsolation,
      scope = this.storageConfig.defaultScope || 'module',
      pageType = options?.pageType ?? 'default',
    } = options || {}

    const separator = this.storageConfig.keySeparator || '::'
    const parts: string[] = []

    // 按作用域构建键前缀
    switch (scope) {
      case 'global':
        break
      case 'domain':
        if (useDomainIsolation)
          parts.push(this.domain)
        break
      case 'pageType':
        if (useDomainIsolation)
          parts.push(this.domain)
        parts.push(pageType)
        break
      case 'module':
        if (useDomainIsolation)
          parts.push(this.domain)
        parts.push(pageType)
        if (useNamespace)
          parts.push(this.id)
        break
    }

    return parts.length > 0
      ? `${parts.join(separator)}${separator}${key}`
      : key
  }

  /**
   * 判断是否应该包含某个键
   * @param key 存储键名
   * @param currentDomain 当前域名
   * @param options 作用域选项
   */
  private shouldIncludeKey(
    key: string,
    currentDomain: string,
    options?: EnhancedOptionsConfig,
  ): boolean {
    const {
      useNamespace = this.storageConfig.useNamespace,
      useDomainIsolation = this.storageConfig.useDomainIsolation,
      includeGlobal = false,
      prefix = undefined,
    } = options || {}

    // 检查域名隔离
    if (useDomainIsolation && !key.startsWith(`${currentDomain}`)) {
      return false
    }

    // 检查命名空间
    if (useNamespace) {
      const domainPattern = this.storageConfig.namespaceKeyStrategy === 'prefix'
        ? `${this.id}${this.storageConfig.keySeparator}`
        : `${this.storageConfig.keySeparator}${this.id}`

      if (!key.includes(domainPattern)) {
        return false
      }
    }

    // 检查全局键
    if (!useNamespace && !useDomainIsolation && includeGlobal) {
      return true
    }

    // 检查前缀
    return !(prefix && !this.getDisplayKey(key, options).startsWith(prefix))
  }

  /**
   * 获取显示用的键名（去除前缀/后缀）
   * @param key 原始键名
   * @param options 作用域选项
   */
  private getDisplayKey(key: string, options?: EnhancedOptionsConfig): string {
    const {
      useNamespace = this.storageConfig.useNamespace,
      useDomainIsolation = this.storageConfig.useDomainIsolation,
      scope = this.storageConfig.defaultScope,
      pageType = this.storageConfig.pageType,
    } = options || {}

    // 去除域名
    if (useDomainIsolation) {
      if (key.startsWith(`${this.domain}${this.storageConfig.keySeparator}`)) {
        key = key.replace(`${this.domain}${this.storageConfig.keySeparator}`, '')
      }
    }

    // 去除命名空间
    if (useNamespace) {
      const namePattern = this.storageConfig.namespaceKeyStrategy === 'prefix'
        ? `${this.id}${this.storageConfig.keySeparator}`
        : `${this.storageConfig.keySeparator}${this.id}`

      key = key.replace(namePattern, '')
    }

    // 去除页面类型前缀
    if (scope === 'pageType') {
      key = key.replace(`${pageType}${this.storageConfig.keySeparator}`, '')
    }

    return key
  }

  /**
   * 获取作用域描述（用于日志）
   * @param options 作用域选项
   */
  private getScopeDescription(options?: EnhancedOptionsConfig): string {
    const useNamespace = options?.useNamespace ?? this.storageConfig.useNamespace
    const useDomainIsolation = options?.useDomainIsolation ?? this.storageConfig.useDomainIsolation
    const includeGlobal = options?.includeGlobal ?? false

    const scopes: string[] = []

    if (useNamespace)
      scopes.push('模块隔离')
    if (useDomainIsolation)
      scopes.push('域名隔离')
    if (includeGlobal)
      scopes.push('包含全局')
    if (scopes.length === 0)
      scopes.push('全局')

    return scopes.join(' + ')
  }
}
